﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ntfs = Trinet.Core.IO.Ntfs;
using System.IO;

namespace SharpShare.Storage.FileSystem {
    public sealed class NtfsFileMetadataProvider : IFileMetadataProvider {
        private NtfsFileMetadataProvider() {

        }

        #region IFileMetadataProvider Members

        public IEnumerable<string> List(string path) {
            return ListMetadataStreamInfos(path).Select(i => UnescapeMetdataStreamName(i.Name));
        }

        public Stream Open(string path, string name, StorageFileAccess access, StorageFileAccess share, StorageFileMode mode) {
            Ntfs.AlternateDataStreamInfo info = GetMetadataStreamInfo(path, name);

            if (!info.Exists && mode == StorageFileMode.OpenExisting) {
                return null;
            }

            Stream stream = info.Open(FileMode.OpenOrCreate, access.MapToFileAccess(), share.MapToFileShare());

            return stream;
        }

        public bool Remove(string path, string name) {
            Ntfs.AlternateDataStreamInfo info = GetMetadataStreamInfo(path, name);
            if (!info.Exists) {
                return false;
            }

            return info.Delete();
        }

        #endregion

        private static Ntfs.AlternateDataStreamInfo GetMetadataStreamInfo(string path, string name) {
            path = PathUtils.Canonicalize(path);

            string escapedName = EscapeMetadataStreamName(name);
            Ntfs.AlternateDataStreamInfo info = Ntfs.FileSystem.GetAlternateDataStream(path, escapedName);

            return info;
        }
        private static IEnumerable<Ntfs.AlternateDataStreamInfo> ListMetadataStreamInfos(string path) {
            path = PathUtils.Canonicalize(path);

            var infos = Ntfs.FileSystem.ListAlternateDataStreams(path)
                .Where(i => UnescapeMetdataStreamName(i.Name) != null);

            return infos;
        }

        private const string MetadataStreamPrefix = "sharpshare_";

        internal static string EscapeMetadataStreamName(string name) {
            return PathUtils.EscapeFilename(MetadataStreamPrefix + name);
        }
        internal static string UnescapeMetdataStreamName(string name) {
            name = PathUtils.UnescapeFilename(name);

            if (!name.StartsWith(MetadataStreamPrefix)) {
                return null;
            }

            name = name.Remove(0, MetadataStreamPrefix.Length);

            return name;
        }


        static NtfsFileMetadataProvider _instance;

        public static NtfsFileMetadataProvider Provider {
            get {
                lock (typeof(NtfsFileMetadataProvider)) {
                    if (_instance == null)
                        _instance = new NtfsFileMetadataProvider();

                    return _instance;
                }
            }
        }


    }
}
